在JavaScript中,实现继承有多种方式。这些方式随着ECMAScript标准的演进而逐渐改进和标准化。以下是几种常见的继承方式:
原型链继承(Prototypal Inheritance): 虽然这不是传统意义上的“类继承”,但它是JavaScript早期实现继承的一种方式。通过将一个对象的原型设置为另一个对象,从而实现继承。
function Parent() { this.property = 'parent'; } Parent.prototype.getParentProperty = function() { return this.property; }; function Child() { Parent.call(this); // 借用构造函数继承属性 this.property = 'child'; } Child.prototype = new Parent(); // 原型链继承方法 Child.prototype.constructor = Child; // 修正constructor指向 var child = new Child(); console.log(child.getParentProperty()); // 输出 'parent'(通过原型链继承的方法) console.log(child.property); // 输出 'child'(自己的属性)
借用构造函数继承(Constructor Stealing/Borrowing): 也称为“经典继承”或“伪类继承”。通过在子类的构造函数中调用父类的构造函数,实现父类属性的继承。但这种方法无法继承父类原型上的方法。
function Parent(name) { this.name = name; this.colors = ['red', 'blue', 'green']; } function Child(name, age) { Parent.call(this, name); // 借用Parent构造函数 this.age = age; } var child = new Child('John', 18); console.log(child.name); // 输出 'John' console.log(child.age); // 输出 18 console.log(child.colors); // 输出 ['red', 'blue', 'green']
组合继承(Combination Inheritance): 结合了原型链继承和借用构造函数继承的优点,既继承了父类的实例属性,又继承了父类原型上的方法。这是JavaScript中最常用的继承模式。
function Parent(name) { this.name = name; this.colors = ['red', 'blue', 'green']; } Parent.prototype.getName = function() { return this.name; }; function Child(name, age) { Parent.call(this, name); // 借用构造函数继承属性 this.age = age; } Child.prototype = new Parent(); // 原型链继承方法 Child.prototype.constructor = Child; // 修正constructor指向 Child.prototype.getAge = function() { return this.age; }; var child = new Child('John', 18); console.log(child.getName()); // 输出 'John' console.log(child.getAge()); // 输出 18 console.log(child.colors); // 输出 ['red', 'blue', 'green']
原型式继承(Prototypal Inheritance with Object.create): 使用
Object.create
方法创建对象,并指定其原型。这是ES5引入的方法,可以更方便地实现原型链继承。var parent = { name: 'parent', colors: ['red', 'blue', 'green'] }; var child = Object.create(parent); child.name = 'child'; child.age = 18; console.log(child.name); // 输出 'child' console.log(child.colors); // 输出 ['red', 'blue', 'green'](共享引用)
寄生组合式继承(Parasitic Combination Inheritance): 这是组合继承的优化版本,通过借用构造函数来继承属性,并使用寄生式继承来继承父类原型上的方法,避免了组合继承中父类实例的重复创建。
function Parent(name) { this.name = name; this.colors = ['red', 'blue', 'green']; } Parent.prototype.getName = function() { return this.name; }; function Child(name, age) { Parent.call(this, name); // 借用构造函数继承属性 this.age = age; } Child.prototype = Object.create(Parent.prototype); // 寄生式继承原型 Child.prototype.constructor = Child; // 修正constructor指向 Child.prototype.getAge = function() { return this.age; }; var child = new Child('John', 18); console.log(child.getName()); // 输出 'John' console.log(child.getAge()); // 输出 18 console.log(child.colors); // 输出 ['red', 'blue', 'green']
类继承(Class Inheritance): ES6引入了
class
语法,使得继承更加直观和易读。class
语法在内部实际上是基于原型链实现的。class Parent { constructor(name) { this.name = name; this.colors = ['red', 'blue', 'green']; } getName() { return this.name; } } class Child extends Parent { constructor(name, age) { super(name); // 调用父类的构造函数 this.age = age; } getAge() { return this.age; } } const child = new Child('John', 18); console.log(child.getName()); // 输出 'John' console.log(child.getAge()); // 输出 18 console.log(child.colors); // 输出 ['red', 'blue', 'green']
每种方式都有其优点和缺点,开发者可以根据具体的需求选择合适的继承方式。